//@HERRICK ONG ZHI PING A0099371U

#include <iostream>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QtTest/QTest>

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    currentSignal = LogicReply::SignalType::NONE; //set initial signal
    setWindowFlags(Qt::FramelessWindowHint); //set borderless window frame
    setAttribute(Qt::WA_TranslucentBackground); //set translucent background other than QFrames

    hideAllWidgets();
    isHidden = false;
    fadeAnimation();
}

MainWindow::~MainWindow()
{
    delete ui;
}

//initializes the session by calling Logic.load. Displays corrupted save data if any, if not it displays urgent tasks.
//Precon: None
//Postcon: Calls logic.Load, displays corrupt strings if any occurred during loading, else loads urgent tasks if any.
void MainWindow::initializeSession()
{
    QVector<QString> corruptStrings;
    logicResult = officeLogic.loadSession(corruptStrings);

    if (!corruptStrings.empty()) {
        displayCorruptStrings(corruptStrings);
        ui->feedbackBar->setText(INITIALIZE_CORRUPTED);
    }
    else if (logicResult.getTaskList().empty()) {
        ui->feedbackBar->setText(INITIALIZE_NOURGENT);
    }
    else {
        refreshDisplay();
        ui->feedbackBar->setText(INITIALIZE_URGENT);
    }

    GUILogger.setFileName(FILE_NAME_UI_LOGGER);
}

//Displays tasks corrupted during loading. Displays them as "floating tasks" at the start of the session.
//Precon: Session loaded, corrupted tasks found upon loading
//Postcon: Corrupted tasks displayed as floating tasks at start of session
//Called by: initializeSession
void MainWindow::displayCorruptStrings(QVector<QString> corruptStrings)
{
    vector<QString> corruptStringsQVec;
    QString corruptStringQ;
    int vecSize = corruptStrings.size();
    QString taskNum;

    for (int i = 0; i < vecSize; i++) {
        corruptStringsQVec.push_back(corruptStringQ);
    }

    for (int i = 0; i < vecSize; i++) {
        ui->listTask->addItem(corruptStringsQVec[i]);
        taskNum = QString::number(i);
        ui->listTaskNum->addItem(taskNum);
    }

    fadeAnimation();
    showStandardWidgets();
}

//Action that is taken whenever the enter key is pressed on your input bar.
//Precon: Enter pressed on input bar
//Postcon: if there is text on the input bar, parseSignal is called
void MainWindow::on_inputBar_returnPressed()
{
    dataEntryQ = ui->inputBar->text();

    if (dataEntryQ != "") {
        parseSignal();
    }
}

//Takes currentSignal and executes different functions depending on what the current signal is.
//Precon: Enter pressed on input bar
//Postcon: currentSignal parsed, exeuteInput or executeTaskDirect called
//Called by: on_inputBar_returnPressed
void MainWindow::parseSignal()
{
    switch (currentSignal) {
    case (LogicReply::SignalType::NONE):
        executeInput();
        break;

    case (LogicReply::SignalType::CALL_SEARCH_DELETE):
    case (LogicReply::SignalType::CALL_SEARCH_COMPLETE):
    case (LogicReply::SignalType::CALL_SEARCH_MODIFY):
    case (LogicReply::SignalType::CALL_COMPLETE):
    case (LogicReply::SignalType::CALL_MODIFY):
    case (LogicReply::SignalType::CALL_DELETE):        
    case (LogicReply::SignalType::CALL_DISPLAY):
        executeTaskDirect();
        break;
    }

}

//Standard UI-Logic interaction. Takes text from inputBar and feeds it to logic's executeCommand function.
//Precon: CurrentSignal is NONE, text in inputbar, return pressed
//Postcon: Text in inputbar fed to logic.executeCommand
//Called by: parseSignal
void MainWindow::executeInput()
{
    clearWidgets();

    dataEntryQ = ui->inputBar->text();
    if (dataEntryQ != NULL)
    {
        logicResult = officeLogic.executeCommand(dataEntryQ);
        displayFeedback();

        refreshDisplay();
    }
}

//Standard UI-Logic interaction. Takes text from inputBar and feeds it to logic's
//other execute functions (delete/modify/complete/display) and bypassing executeInput, depending on what currentSignal is.
//Precon: CurrentSignal is CALL_ANYTHING, text in inputbar, return pressed
//Postcon: Text in inputbar fed to logic.executeDisplay/Modify/Complete/Delete
//Called by: parseSignal
void MainWindow::executeTaskDirect()
{
    clearWidgets();

    dataEntryQ = ui->inputBar->text();
    int TaskRef, index;
    QString index_Str = ui->inputBar->text();
    QString whitespace = WHITESPACE;

    if (dataEntryQ != NULL) {

        switch (currentSignal) {
        case (LogicReply::SignalType::CALL_DISPLAY):
            logicResult = officeLogic.executeDisplay(dataEntryQ);
            break;

        case (LogicReply::SignalType::CALL_DELETE):
            if (digitChecker.isDigit(dataEntryQ)) {
                TaskNum = dataEntryQ.toInt();
                TaskRef = TaskList[TaskNum-1].getTaskRef();
                logicResult = officeLogic.deleteTask(TaskRef);
                break;
            }
            else {
                logicResult.setSignalType(LogicReply::SignalType::NONE);
                ui->feedbackBar->setText(FEEDBACK_ERROR);
                break;
            }
        case (LogicReply::SignalType::CALL_COMPLETE):
            if (digitChecker.isDigit(dataEntryQ)) {
                TaskNum = dataEntryQ.toInt();
                TaskRef = TaskList[TaskNum-1].getTaskRef();
                logicResult = officeLogic.markCompletedTask(TaskRef);
                break;
            }
            else {
                logicResult.setSignalType(LogicReply::SignalType::NONE);
                ui->feedbackBar->setText(FEEDBACK_ERROR);
                break;
            }

        case (LogicReply::SignalType::CALL_MODIFY):
            index = index_Str.indexOf(whitespace);

            if (index != string::npos) {
                index_Str.truncate(index);
            }
            if (digitChecker.isDigit(index_Str)) {
                index = index_Str.toInt();
                TaskRef = TaskList[index-1].getTaskRef();
                dataEntry = dataEntryQ.toStdString();
                logicResult = officeLogic.modifyProperty(TaskRef, dataEntryQ);
                break;
            }
            else {
                logicResult.setSignalType(LogicReply::SignalType::NONE);
                ui->feedbackBar->setText(FEEDBACK_ERROR);
                break;
            }

        case (LogicReply::SignalType::CALL_SEARCH_COMPLETE):
            logicResult = officeLogic.executeComplete(dataEntryQ);
            break;

        case (LogicReply::SignalType::CALL_SEARCH_DELETE):
             logicResult = officeLogic.executeDelete(dataEntryQ);
            break;

        case (LogicReply::SignalType::CALL_SEARCH_MODIFY):
            logicResult = officeLogic.executeModify(dataEntryQ);
            break;
            }

        displayFeedback();

        refreshDisplay();
    }

}

//Clears all widgets of content in preparation for new user input.
//Precon: New user input
//Postcon: All widgets cleared of data
//Called by: Start of execututeInput, executeTaskDirect
void MainWindow::clearWidgets()
{
    ui->listTask->clear();
    ui->listTaskNum->clear();
    ui->listDate->clear();
    ui->listEndTime->clear();
    ui->listStartTime->clear();
    ui->listDaySchedule->clear();
    ui->listStatus->clear();

    if (currentSignal == LogicReply::SignalType::NONE)
    {
        TaskList.clear();
    }
}

//Displays feedback from logicReply class in the prompt bar.
//Precon: Received updated logicReply class from logic, feedback in logicReply not empty
//Postcon: Feedback string from logicReply displayed in prompt bar
//Called by: refreshDisplay
void MainWindow::displayFeedback()
{
    GUILogger.logInfo(logicResult.getFeedback().toStdString());
    resultQ = logicResult.getFeedback();

//    assert(!(resultQ.isEmpty()));
//    assert(!(resultQ.isNull()));

    if (resultQ.isEmpty() || (resultQ.isNull())) {
        ui->feedbackBar->setText(FEEDBACK_ERROR);
    }
    else {
        ui->feedbackBar->setText(resultQ);
    }

    ui->inputBar->clear();
}

//Refreshes the entire UI in preparation for the next user input.
//Precon: User input executed
//Postcon: display results (if present) are displayed, appropriate widgets hidden and displayed, currentsignal modified to match user's last command
//Called by: End of executeInput, executeTaskDirect
void MainWindow::refreshDisplay() {
    TaskList = logicResult.getTaskList();
    displayAllOutput();
    toggleHide();
    changeSignal();
}

//Displays output depending on what the DisplayType in the logicReply class is.
//Precon: User input processed and logicReply class returned from logic, tasklist in logicReply class not empty
//Postcon: TaskList displayed, either in standard format or date format
//Called by: refreshDisplay
void MainWindow::displayAllOutput() {

    clearWidgets();
    TaskList = logicResult.getTaskList();

    if ((logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_ALL) ||
            (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_DEADLINE) ||
            (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_MEETING) ||
            (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_FLOAT) ||
            (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_OVERDUE) ||
            (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_URGENT))

    {
        displayStandardOutput(TaskList);
    }

    else if (logicResult.getDisplayType() == LogicReply::DisplayType::DISPLAY_DATE)    {
        displayDateOutput(TaskList);
    }

}

//Standard Widgets displayed showing task descriptions, task numbers, and task times (if applicable)
//Precon: User input processed and logicReply class returned from logic, taskList in logicReply class not empty
//Precon2: DisplaySignal is not DISPLAY_DATE or DISPLAY_NONE
//Postcon: TaskList displayed in standard format showing task title/number/date/time/status (where applicable)
//Called by: displayAllOutput
void MainWindow::displayStandardOutput(QVector<Task> TaskList) {
    stringstream ss;
    int TaskNumber;
    Task::TaskStatus deadlineTaskStatus;

    //Adding Task Title
    for (int i = 0; i < TaskList.size(); i++)
    {
        dataEntryQ = TaskList[i].getTitle();
        ui->listTask->addItem(dataEntryQ);
    }

    //Adding Task Number
    for (int i = 0; i < TaskList.size(); i++)
    {
        TaskNumber = i+1;
        ss << TaskNumber;
        dataEntry = ss.str();
        dataEntryQ = dataEntry.c_str();
        ui->listTaskNum->addItem(dataEntryQ);
        ss.str("");
    }

    //Adding Task Date/StartTime/EndTime
    for (int i = 0; i < TaskList.size(); i++)
    {
        Task::TaskType typeOfTask = TaskList[i].getTaskType();

        switch (typeOfTask) {
        case Task::TaskType::FLOATING:
            ui->listDate->addItem("-");
            ui->listStartTime->addItem("-");
            ui->listEndTime->addItem("-");

            deadlineTaskStatus = TaskList[i].getTaskStatus();
            updateStatusOnWidget(deadlineTaskStatus, i);

            break;

        case Task::TaskType::DEADLINE:
            dataEntryQ = TaskList[i].getStartDate().toString();
            ui->listDate->addItem(dataEntryQ);

            dataEntryQ = TaskList[i].getEndTime().toString();
            ui->listEndTime->addItem(dataEntryQ);

            ui->listStartTime->addItem("-");

            //Adding deadline status
            deadlineTaskStatus = TaskList[i].getTaskStatus();
            updateStatusOnWidget(deadlineTaskStatus, i);

            break;

        case Task::TaskType::MEETING:
            dataEntryQ = TaskList[i].getStartDate().toString();
            ui->listDate->addItem(dataEntryQ);

            dataEntryQ = TaskList[i].getEndTime().toString();
            ui->listEndTime->addItem(dataEntryQ);

            dataEntryQ = TaskList[i].getStartTime().toString();
            ui->listStartTime->addItem(dataEntryQ);

            deadlineTaskStatus = TaskList[i].getTaskStatus();
            updateStatusOnWidget(deadlineTaskStatus, i);
            break;

        }

    }
}

//Date widget displayed showing deadlines and meetings in a schedule format, deadlines in red cells and meeting timespans in green cells
//Precon: User input processed and logicReply class returned from logic, taskList in logicReply class not empty
//Precon2: DisplaySignal is DISPLAY_DATE
//Postcon: TaskList displayed in date format, meetings and deadlines shown in schedule format
//Called by: displayAllOutput
void MainWindow::displayDateOutput(QVector<Task> TaskList) {
    QStringList taskLabels;
    QString toAdd;
    QTableWidgetItem *colourCell;
    int startHour, endHour;
    QTime startTime, endTime;
    Task::TaskType taskType;
    ui->listDaySchedule->setRowCount(TaskList.size());

    for(int i = 0; i < TaskList.size(); i++) {
        toAdd = TaskList[i].getTitle();
        taskLabels << toAdd;
    }

    ui->listDaySchedule->setVerticalHeaderLabels(taskLabels);

    for(int i = 0; i < TaskList.size(); i++) {
        //colouring
        taskType = TaskList[i].getTaskType();

        switch (taskType) {

        case Task::TaskType::DEADLINE:
            colourCell = new QTableWidgetItem();
            endTime = TaskList[i].getEndTime();
            endHour = endTime.hour();

            colourCell->setBackgroundColor(Qt::red);
            toAdd = QString::number(endTime.minute());

            if (endTime.minute() < 10) {
                toAdd.prepend("0");
            }

            colourCell->setText(toAdd);
            colourCell->setTextAlignment(Qt::AlignCenter);
            ui->listDaySchedule->setItem(i, endHour, colourCell);

            break;

        case Task::TaskType::MEETING:
            startTime = TaskList[i].getStartTime();
            endTime = TaskList[i].getEndTime();
            startHour = startTime.hour();
            endHour = endTime.hour();

            //set start
            colourCell = new QTableWidgetItem();
            colourCell->setBackgroundColor(Qt::green);
            toAdd = QString::number(startTime.minute());

            if (startTime.minute() < 10) {
                toAdd.prepend("0");
            }

            colourCell->setText(toAdd);
            colourCell->setTextAlignment(Qt::AlignCenter);
            ui->listDaySchedule->setItem(i, startHour, colourCell);

            //set end
            colourCell = new QTableWidgetItem();
            colourCell->setBackgroundColor(Qt::green);
            toAdd = QString::number(endTime.minute());

            if (endTime.minute() < 10) {
                toAdd.prepend("0");
            }

            colourCell->setText(toAdd);
            colourCell->setTextAlignment(Qt::AlignCenter);
            ui->listDaySchedule->setItem(i, endHour, colourCell);

            //set middle
            for (int j = startHour+1; j < endHour; j++) {
                colourCell = new QTableWidgetItem();
                colourCell->setBackgroundColor(Qt::green);

                ui->listDaySchedule->setItem(i, j, colourCell);
            }

            break;

        }
    }
}

//Displays only the widgets relevant to the tasklist given and hides everything else.
//Precon: User input given
//Postcon: Relevant widgets displayed, other widgets hidden.
//Called by: refreshDisplay
void MainWindow::toggleHide()
{
    if (!TaskList.empty()) {
            LogicReply::DisplayType displayType = logicResult.getDisplayType();

            switch (displayType){

            case LogicReply::DisplayType::DISPLAY_DATE:
                hideStandardWidgets();
                showDateWidgets();
                if (isHidden)
                {
                fadeAnimation();
                }
                break;

            case LogicReply::DisplayType::DISPLAY_FLOAT:
                hideDateWidgets();
                hideMeetingWidgets();
                hideDeadlineWidgets();
                showStandardWidgets();
                if (isHidden)
                {
                fadeAnimation();
                }
                break;

            case LogicReply::DisplayType::DISPLAY_DEADLINE:
                hideDateWidgets();
                hideMeetingWidgets();
                showDeadlineWidgets();
                showStandardWidgets();
                adjustDeadlineSize();
                if (isHidden)
                {
                fadeAnimation();
                }
                break;

            case LogicReply::DisplayType::DISPLAY_OVERDUE:
            case LogicReply::DisplayType::DISPLAY_URGENT:
            case LogicReply::DisplayType::DISPLAY_ALL:
            case LogicReply::DisplayType::DISPLAY_MEETING:
                hideDateWidgets();
                showMeetingWidgets();
                showDeadlineWidgets();
                showStandardWidgets();
                if (isHidden)
                {
                fadeAnimation();
                }
                break;

            case LogicReply::DisplayType::DISPLAY_NONE:
                if (!isHidden) {
                    fadeAnimation();
                }
                break;

            default:
                if (!isHidden) {
                    fadeAnimation();
                }
                break; //should not occur

        }
    }
    else {
        if (!isHidden) {
            fadeAnimation();
        }

    }
}

//Updates signal to change between executeInput and executeTaskDirect when parsed again.
//Precon: User input completely processed
//Postcon: currentSignal changed to reflect any signal from user's last input
//Called by: refreshDisplay
void MainWindow::changeSignal() {
    currentSignal = logicResult.getSignalType();
}

//Hides all widgets in preparation for refreshing UI
//Precon: None. Should only be called by refreshDisplay.
//Postcon: All widgets for displaying tasks hidden.
//Called by: initializeSession
void MainWindow::hideAllWidgets() {

    hideStandardWidgets();
    hideDateWidgets();

    ui->horSpacer1->changeSize(18, 20);
    ui->frameList->setStyleSheet("background:transparent; border: transparent;");

}

//Hides date widgets
//Precon: None
//Postcon: Date schedule widget hidden
//Called by: toggleHide
void MainWindow::hideDateWidgets() {
    ui->listDaySchedule->hide();
}

//Hides standard widgets
//Precon: None
//Postcon: lists for Title/TaskNum/Date/StartTime/EndTime/Status hidden
//Called by: toggleHide
void MainWindow::hideStandardWidgets() {
    ui->listTask->hide();
    ui->listTaskNum->hide();
    ui->listStatus->hide();

    ui->labelTask->hide();
    ui->labelTaskNum->hide();
    ui->labelStatus->hide();

    hideDeadlineWidgets();
    hideMeetingWidgets();
}

//Hides deadline widgets
//Precon: None
//Postcon: EndTime/Date Widgets hidden
void MainWindow::hideDeadlineWidgets()
{
    ui->listEndTime->hide();
    ui->listDate->hide();

    ui->labelDate->hide();
    ui->labelEndTime->hide();
}

//Hides meeting widgets
//Precon: None
//Postcon: StartTime widget hidden
void MainWindow::hideMeetingWidgets() {
    ui->listStartTime->hide();
    ui->labelStartTime->hide();
}

//Shows widgets for display for all tasks other than display date.
//Precon: UI Refresh, tasklist not empty
//Postcon: TaskList, TaskNumList, TaskStatusList displayed.
//Called by: toggleHide, displayCorruptStrings
void MainWindow::showStandardWidgets()
{
    ui->listTask->show();
    ui->listTaskNum->show();

    ui->labelTask->show();
    ui->labelTaskNum->show();

    ui->labelStatus->show();
    ui->listStatus->show();

    ui->frameList->setStyleSheet("background:black; frameList {border: 3px solid grey;}");
    ui->centralWidget->setStyleSheet("QLabel { color:white; }");

    ui->horSpacer1->changeSize(23, 20);
}

//Shows widgets for displaying for deadline tasks.
//Precon: UI Refresh, tasklist has deadline tasks inside
//Postcon: EndTimeList, DateList displayed.
//Called by: toggleHide
void MainWindow::showDeadlineWidgets()
{
    ui->listDate->show();
    ui->listEndTime->show();

    ui->labelDate->show();
    ui->labelEndTime->show();
}

//Shows widgets for displaying for meeting tasks.
//Precon: UI Refresh, tasklist has meeting tasks inside
//Postcon: StartTimeList displayed.
//Called by: toggleHide
void MainWindow::showMeetingWidgets()
{
    ui->listStartTime->show();
    ui->labelStartTime->show();
}

//Adjusts space between labels to centralize labels in Display Deadline scenario.
//Precon: None
//Postcon: space between labels adjusted
//Called by: toggleHide
void MainWindow::adjustDeadlineSize()
{
    ui->horSpacer1->changeSize(3, 20);
}

//Shows widgets for displaying a date.
//Precon: UI Refresh, display date given as user input
//Postcon: Schedule for the given day displayed.
//Called by: toggleHide
void MainWindow::showDateWidgets()
{
    QStringList hourLabels;
    hourLabels << "00" << "01" << "02" << "03" << "04" << "05" << "06" << "07" << "08" << "09" << "10" << "11" << "12" << "13" << "14" << "15" << "16" << "17" << "18" << "19" << "20" << "21" << "22" << "23" << "24";
    ui->listDaySchedule->show();
    ui->listDaySchedule->setHorizontalHeaderLabels(hourLabels);

    int blankWidth = ui->listDaySchedule->width() - ui->listDaySchedule->verticalHeader()->width();

    for (int i = 0; i < 24; i++)
    {
        ui->listDaySchedule->setColumnWidth(i, blankWidth/24);

    }

    ui->frameList->setStyleSheet("background:black;");

}

//Updates listStatus widget with task statuses (Urgent, Overdue, Normal, Complete)
//Precon: taskStatus present, index one larger than current widget list size
//Postcon: listStatus widget adds an entry indicating task status for task at the given index
//Called by: displayStandardOutput
void MainWindow::updateStatusOnWidget(Task::TaskStatus deadlineTaskStatus, int index)
{
    switch(deadlineTaskStatus) {

    case Task::TaskStatus::APPROACH1:
        ui->listStatus->addItem("Today");
        ui->listStatus->item(index)->setForeground(Qt::red);
        break;

    case Task::TaskStatus::APPROACH2:
        ui->listStatus->addItem("1 day");
        ui->listStatus->item(index)->setForeground(Qt::yellow);
        break;

    case Task::TaskStatus::APPROACH3:
        ui->listStatus->addItem("2 days");
        ui->listStatus->item(index)->setForeground(Qt::yellow);
        break;

    case Task::TaskStatus::COMPLETE:
        ui->listStatus->addItem("Done");
        ui->listStatus->item(index)->setForeground(Qt::green);
        break;

    case Task::TaskStatus::OVERDUE:
        ui->listStatus->addItem("Over");
        ui->listStatus->item(index)->setForeground(Qt::red);
        break;

    case Task::TaskStatus::NORMAL:
        ui->listStatus->addItem("-");
        break;

    default:
        ui->listStatus->addItem("E"); //Error
        break;
    }

}

//For unit testing. Returns feedback string that comes from executing the input command into logic class.
//Precon: command is given
//Postcon: Feedback string given from executing the command string
//Called by: Unit testing main.cpp
QString MainWindow::executeInputTest(QString command)
{
    clearWidgets();

    dataEntryQ = command;
    if (dataEntryQ != NULL)
    {
        logicResult = officeLogic.executeCommand(dataEntryQ);
        displayFeedback();

        refreshDisplay();
    }

	return resultQ;
}

//Called everytime text in inputBar is edited by the user. Parses the text currently typed.
//Precon: None
//Postcon: parseText called for parsing
//Called by: Every time user edits his command in inputBar
void MainWindow::on_inputBar_textEdited(const QString &arg1)
{
    parseText(arg1);
}

//displays feedback string corresponding to the command typed by user
//Precon: user types something in inputbar
//Postcon: depending on what is being typed, sends parsing to parseText_None/Modify. Cases can be added as needed.
//Called by: on_inputBar_textEdited
void MainWindow::parseText(const QString &arg1)
{
    switch (currentSignal) {
    case (LogicReply::SignalType::NONE):
        parseText_None(arg1);
        break;

    case (LogicReply::SignalType::CALL_MODIFY):
        parseText_Modify(arg1);
        break;
    }
}

//Displays feedback string corresponding to comamand typed by user in currentSignal = NONE scenario.
//Precon: Text edited, currentSignal = NONE
//Postcon: Live feedback strings for add/delete/modify/display/complete/search given.
//Called by: parseText
void MainWindow::parseText_None(const QString &arg1)
{
    if (arg1.startsWith(COMMAND_ADD, Qt::CaseInsensitive)) {
        int delimiterCount = arg1.count(DELIMITER_SLASH, Qt::CaseInsensitive);

        if (delimiterCount == 0) {
            ui->feedbackBar->setText(FEEDBACK_ADD);
        }
        else if (delimiterCount == 1) {
            ui->feedbackBar->setText(FEEDBACK_DATE);
        }
        else if ((delimiterCount == 2) || (delimiterCount == 3)) {
            ui->feedbackBar->setText(FEEDBACK_TIME);
        }
        else {
            ui->feedbackBar->setText(FEEDBACK_DELIMITERS);
        }

    }

    else if (arg1.startsWith(COMMAND_DELETE, Qt::CaseInsensitive)) {
        ui->feedbackBar->setText(FEEDBACK_DELETE);
    }

    else if (arg1.startsWith(COMMAND_MODIFY, Qt::CaseInsensitive)) {
        ui->feedbackBar->setText(FEEDBACK_MODIFY);
    }

    else if (arg1.startsWith(COMMAND_DISPLAY, Qt::CaseInsensitive)) {
        int dateCount = arg1.count(COMMAND_DATE, Qt::CaseInsensitive);

        if (dateCount == 0) {
        ui->feedbackBar->setText(FEEDBACK_DISPLAY);
        }
        else if (dateCount > 0) {
            ui->feedbackBar->setText(FEEDBACK_DATE);
        }

    }

    else if (arg1.startsWith(COMMAND_COMPLETE, Qt::CaseInsensitive)) {
        ui->feedbackBar->setText(FEEDBACK_COMPLETE);
    }

    else if (arg1.startsWith(COMMAND_SEARCH, Qt::CaseInsensitive)) {
        ui->feedbackBar->setText(FEEDBACK_SEARCH);
    }
}

//Displays feedback string corresponding to comamand typed by user in currentSignal = MODIFY scenario.
//Precon: Text edited, currentSignal = MODIFY
//Postcon: Live feedback strings for modify given when the modify format is required
//Called by: parseText
void MainWindow::parseText_Modify(const QString &arg1)
{
    int delimiterCount = arg1.count(WHITESPACE, Qt::CaseInsensitive);

    if (delimiterCount == 0) {
        ui->feedbackBar->setText(FEEDBACK_MODIFYFORMAT);
    }
    else if (delimiterCount == 1) {
        ui->feedbackBar->setText(FEEDBACK_MODIFYCOMPONENTS);
    }
    else if (delimiterCount == 2) {
        if (arg1.contains(COMMAND_DATE, Qt::CaseInsensitive)) {
            ui->feedbackBar->setText(FEEDBACK_DATE);
        }
        else if (arg1.contains(COMMAND_STARTTIME, Qt::CaseInsensitive)) {
            ui->feedbackBar->setText(FEEDBACK_TIME);
        }
        else if (arg1.contains(COMMAND_ENDTIME, Qt::CaseInsensitive)) {
            ui->feedbackBar->setText(FEEDBACK_TIME);
        }
        else if (arg1.contains(COMMAND_TITLE, Qt::CaseInsensitive)) {
            ui->feedbackBar->setText(FEEDBACK_MODIFYTITLE);
        }
    }

}

//Denotes event where mouse is pressed. Redirects oldPos' position to the current position indicated by the mouse
//Code copied from Internet
void MainWindow::mousePressEvent(QMouseEvent *evt)
{
    oldPos = evt->globalPos();
}

//Denotes event where mouse is dragged while clicked. Enables dragging of UI (borderless UI cannot be dragged normally)
//Code copied from Internet
void MainWindow::mouseMoveEvent(QMouseEvent *evt)
{
    const QPoint delta = evt->globalPos() - oldPos;

    QMainWindow::move(QMainWindow::x()+delta.x(), QMainWindow::y()+delta.y());
    oldPos = evt->globalPos();
}

//Animated the fading of the widget frame in and out depending on the current state of isHidden.
//Called by: displayCorruptStrings, toggleHide;
//Code copied from Internet and edited slightly
void MainWindow::fadeAnimation()
{
    int origOpac, finalOpac;

    if (isHidden)
    {
        origOpac = 0;
        finalOpac = 1.0;
    }
    else
    {
        origOpac = 1.0;
        finalOpac = 0;
    }

    QGraphicsOpacityEffect* opacityEffect = new QGraphicsOpacityEffect(this);
    opacityEffect->setOpacity(origOpac);
    ui->frameList->setGraphicsEffect(opacityEffect);
    QPropertyAnimation* anim = new QPropertyAnimation(this);
    anim->setTargetObject(opacityEffect);
    anim->setPropertyName("opacity");
    anim->setDuration(500);
    anim->setStartValue(opacityEffect->opacity());
    anim->setEndValue(finalOpac);
    anim->setEasingCurve(QEasingCurve::OutQuad);
    anim->start(QAbstractAnimation::DeleteWhenStopped);

    if (isHidden)
    {
        isHidden = false;
    }
    else {
        isHidden = true;
    }
}
